/*******************************************************************************
 * Copyright (c) 2011 SYSTEMA GmbH.
 * All rights reserved.
 *
 * Contributors:
 *     SYSTEMA GmbH - initial API and implementation
 *******************************************************************************/
package de.sr.gwtdemo.client.widgets.console;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.Widget;

import de.sr.gwtdemo.client.widgets.WidgetConstants;
import de.sr.gwtdemo.shared.util.StringUtil;

/**
 * The console to display log messages.
 * 
 * @author jhilde, reinhard
 * @since 01.06.2011
 * @version $Revision$
 * 
 *          $LastChangedDate$ $LastChangedBy$
 */
public class Console extends Composite {

	interface ConsoleAdapterUiBinder extends UiBinder<Widget, Console> {
	}

	private static ConsoleAdapterUiBinder uiBinder = GWT.create(ConsoleAdapterUiBinder.class);

	private static Console instance = null;

	private List<String> logs = new ArrayList<String>();

	private int maxNumberOfLogs = 200;

	private int newLogLinesCount = 0;

	private int errorCount = 0;

	@UiField
	HTMLPanel console;

	@UiField
	FocusPanel consoleHeader;

	@UiField
	TextArea textArea;

	@UiField
	Button clearButton;

	@UiField
	HTML headerTitle;

	public Console() {
		initWidget(uiBinder.createAndBindUi(this));

	}

	public static Console getInstance() {
		if (instance == null) {
			instance = new Console();
		}
		return instance;
	}

	@UiHandler("clearButton")
	void clearBtnClicked(ClickEvent ce) {
		logs.clear();
		updateLog();
	}

	@UiHandler("consoleHeader")
	void consoleHeaderClicked(ClickEvent ce) {
		toggleExpand();
	}

	public int getMaxNumberOfLogs() {
		return maxNumberOfLogs;
	}

	@Override
	protected void initWidget(Widget widget) {
		super.initWidget(widget);

		// Prevents scroll to bottom errors
		textArea.getElement().setAttribute("wrap", "off");
	}

	public void log(String message, boolean isError) {
		logs.add(message);

		int maxNumberOfLogs = getMaxNumberOfLogs();
		if (maxNumberOfLogs > 0) {
			while (logs.size() > maxNumberOfLogs) {
				logs.remove(0);
			}
		}

		if (!textArea.isVisible() && isError) {
			errorCount++;
		}
		updateLog();
	}

	protected void scrollToBottom() {
		Element elem = textArea.getElement();
		int scrollTop = elem.getScrollHeight();

		// Note: Does not work on IE7 if "wrap" is "off"
		elem.setScrollTop(scrollTop);
	}

	public void setMaxNumberOfLogs(int maxNumberOfLogs) {
		this.maxNumberOfLogs = maxNumberOfLogs;
	}

	@Override
	public void setVisible(boolean visible) {
		super.setVisible(visible);
		updateLog();
	}

	private void toggleExpand() {
		boolean visible = !textArea.isVisible();
		textArea.setVisible(visible);
		clearButton.setVisible(visible);
		if (visible) {
			console.setWidth(WidgetConstants.INSTANCE.Console_Width_Expanded());
			newLogLinesCount = 0;
			errorCount = 0;
			updateLog(); // scrollToBottom(); and updateTitle(); is done in updateLog
		} else {
			console.setWidth(WidgetConstants.INSTANCE.Console_Width_Collaped());
			updateTitle();
		}
	}

	private void updateLog() {
		// FIXME: not working, correct for SR2
		// if (isVisible())
		//	return;

		// New line as separator is not required (already contained in log)
		String text = StringUtil.mkString(logs, "", "", "");
		textArea.setText(text);

		scrollToBottom();

		if (!textArea.isVisible()) {
			newLogLinesCount++;
		}

		updateTitle();
	}

	private void updateTitle() {
		if (newLogLinesCount > 0) {
			headerTitle.setHTML("Console (" + newLogLinesCount + ")");
			if (errorCount > 0) {
				if (errorCount == 1) {
					headerTitle.setHTML("Console (" + newLogLinesCount + ") - <span style=\"color:red;\">1 Error</span>");
				} else {
					headerTitle.setHTML("Console (" + newLogLinesCount + ") - <span style=\"color:red;\">" + errorCount
							+ " Errors</span>");
				}
			}
		} else {
			headerTitle.setText("Console");
		}
	}

}
